package caidan;

import caidan.data.CategoryData;
import caidan.data.FoodData;
import caidan.res.Resource;
import jinyilw.common.TextTools;
import jinyilw.swing.FontTools;
import jinyilw.swing.NativeTools;
import jinyilw.swing.ResourceManager;
import jinyilw.swing.SwingTools;
import jinyilw.swing.graphics.GraphicsTools;
import jinyilw.swing.image.ImageTools;
import jinyilw.swing.rlaf.ui.RScrollBarUI;
import jinyilw.swing.rlaf.utils.RBorderFactory;
import jinyilw.swing.visuals.Rcomp.ROptionPane;
import jinyilw.swing.visuals.comp.RichTextComp;
import jinyilw.swing.visuals.panel.Position;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FileDialog;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Stroke;
import java.awt.event.ActionEvent;
import java.awt.geom.RoundRectangle2D;
import java.io.File;
import java.util.ArrayList;

public class CategoryPanel extends JComponent
{
	private static final long serialVersionUID = -3764007084925305912L;
	private final JPanel choosePane = SwingTools.createTransBorderPane();
	private final RichTextComp titleComp = new RichTextComp();
	final ContentContainer contentContainer = new ContentContainer();
	private final JScrollPane scrollPane = contentContainer.getScrollPane();
	final Container glassPane = new GlassPanel();
	private JButton addButton;
	ArrayList<FoodPanel> breakfastPanels = new ArrayList<FoodPanel>();
	ArrayList<FoodPanel> otherPanels = new ArrayList<FoodPanel>();
	ArrayList<FoodPanel> choosePanels = new ArrayList<FoodPanel>();

	CategoryData categoryData;
	int maxCol, maxChooseNum;
	final int breakfastChooseNum, otherChooseNum;
	Position[] choosePositions;
	final Position[] breakfastChoosePositions, otherChoosePositions;

	private boolean editable;
	PositionConfiger positionConfiger;
	RoundRectangle2D.Float roundShape;
	MainFrame mainFrame;

	public CategoryPanel(MainFrame frame, CategoryData categoryData,
			PositionConfiger p)
	{
		mainFrame = frame;
		this.categoryData = categoryData;
		positionConfiger = p;
		roundShape = p.roundShape;
		maxCol = p.getMaxColumn();
		maxChooseNum = breakfastChooseNum = categoryData
				.getBreakfastChooseNum();
		otherChooseNum = categoryData.getOtherChooseNum();
		setBorder(RBorderFactory.getDefaultBorder());
		setLayout(null);

		titleComp.setText(categoryData.getCategoryName());
		titleComp.setFont(FontTools.getCustomFont(18));
		titleComp.setForeground(Color.YELLOW);
		titleComp.setImageLocation(SwingConstants.EAST);

		if (categoryData.getCategoryID() != 0)
		{
			titleComp.setImageRolloverAct(true);
			titleComp.addClickOperator((Object o) ->
			{
				if (editable)
					showEditDialog();
			});
		}
		add(titleComp);
		add(glassPane);
		add(scrollPane);
		add(choosePane);

		choosePositions = breakfastChoosePositions = new Position[breakfastChooseNum];
		for (int i = 0; i < breakfastChooseNum; i++)
			breakfastChoosePositions[i] = new Position(positionConfiger);

		otherChoosePositions = new Position[otherChooseNum];
		for (int i = 0; i < otherChooseNum; i++)
			otherChoosePositions[i] = new Position(positionConfiger);

		for (FoodData foodData : categoryData.getAllDatas())
		{
			FoodPanel foodPanel = new FoodPanel(foodData, this);
			if (foodData.isInBreakfast())
				breakfastPanels.add(foodPanel);
			if (foodData.isInOther())
				otherPanels.add(foodPanel);
		}

		categoryData
				.addDataAddedActor((FoodData foodData, Boolean isBreakfast) ->
				{
					addNewFood(foodData, isBreakfast);
				});
	}

	public ArrayList<FoodPanel> getCurrentPanels()
	{
		if (mainFrame.isSelectBreakfast())
			return breakfastPanels;
		return otherPanels;
	}

	public ArrayList<FoodData> getCurrentFoodDatas()
	{
		return categoryData.getCurrentDatas(mainFrame.isSelectBreakfast());
	}

	public Position[] getChoosePositions()
	{
		return choosePositions;
	}

	public String getCategoryName()
	{
		return categoryData.getCategoryName();
	}

	public void count(int d, int m)
	{
		for (int i = 0; i < choosePanels.size(); i++)
			choosePanels.get(i).count(d, m);
	}

	public int[] findFavorite()
	{
		return categoryData.findFavorite();
	}

	public int[] findFavorite(int day, int meal)
	{
		return categoryData.findFavorite(day, meal);
	}

	public int getChooseNumber()
	{
		return choosePanels.size();
	}

	public void chooseBreakfast()
	{
		clearAllChoose();
		positionConfiger.removeAllPositionSetter();
		for (FoodPanel fp : otherPanels)
			contentContainer.remove(fp);

		for (FoodPanel fp : breakfastPanels)
		{
			contentContainer.add(fp);
			positionConfiger.addPositionSetter(fp);
		}
		choosePositions = breakfastChoosePositions;
		maxChooseNum = breakfastChooseNum;
		validate();
		repaint();
	}

	public void chooseOther()
	{
		clearAllChoose();
		positionConfiger.removeAllPositionSetter();
		for (FoodPanel fp : breakfastPanels)
			contentContainer.remove(fp);

		for (FoodPanel fp : otherPanels)
		{
			contentContainer.add(fp);
			positionConfiger.addPositionSetter(fp);
		}
		choosePositions = otherChoosePositions;
		maxChooseNum = otherChooseNum;
		validate();
		repaint();
	}

	private JLabel tipsLabel;
	public void showTips()
	{
		if (tipsLabel == null)
			tipsLabel = new JLabel();
		tipsLabel.setText("最多选择 " + maxChooseNum + " 个。");
		ROptionPane.showMessageDialog(this, tipsLabel, "提示!",
				JOptionPane.OK_OPTION);
	}

	public void setEditable(boolean editable)
	{
		if (this.editable == editable)
			return;
		this.editable = editable;
		if (editable)
		{
			clearAllChoose();
			if (addButton == null)
			{
				addButton = new JButton("添加新菜单", Resource.addIcon);
				addButton.setBounds((getWidth() - 105) / 2,
						choosePane.getY() + 20, 105, 32);
				addButton.addActionListener((ActionEvent e) ->
				{
					addNew();
				});
				categoryData.setEdited(true);
			}
			titleComp.setImage(Resource.editcategoryIcon);
			remove(choosePane);
			add(addButton);
		} else
		{
			titleComp.setImage(null);
			remove(addButton);
			if (!MainApp.isExtendMode)
				add(choosePane);
		}
		for (FoodPanel cp : breakfastPanels)
			cp.setEditable(editable);
		for (FoodPanel cp : otherPanels)
			cp.setEditable(editable);
	}

	public void setExtendMode(boolean b)
	{
		if (b)
		{
			positionConfiger.setPramater(MainApp.extendWW, MainApp.extendHH,
					MainApp.extendSS);
			remove(choosePane);
		} else
		{
			positionConfiger.setMaxColumn(maxCol);
			if (!editable)
				add(choosePane);
		}
	}

	public void choose(FoodPanel fp)
	{
		int li = choosePanels.size();
		if (li < maxChooseNum)
		{
			contentContainer.remove(fp);
			glassPane.add(fp);
			fp.setLocation(fp.getConvertedPoint());
			fp.repaint();
			fp.moveToInThread(choosePositions[li]);
			choosePanels.add(fp);
			choosePositions[li].setUsed(true);
			fp.choose();
		} else
		{
			showTips();
		}
	}

	public void unchoose(FoodPanel fp)
	{
		fp.unchoose();
		new Thread(() ->
		{
			fp.moveTo(fp.getConvertedPoint());
			glassPane.remove(fp);
			contentContainer.add(fp);
			fp.updatePosition();
		}).start();

		int li = choosePanels.indexOf(fp);
		for (int i = li + 1; i < choosePanels.size(); i++)
		{
			choosePanels.get(i).moveToInThread(choosePositions[i - 1]);
		}
		choosePanels.remove(li);
		choosePositions[choosePanels.size()].setUsed(false);
		glassPane.repaint();
	}

	public void clearAllChoose()
	{
		FoodPanel fp;
		for (int i = choosePanels.size() - 1; i >= 0; i--)
		{
			choosePositions[i].setUsed(false);
			fp = choosePanels.get(i);
			glassPane.remove(fp);
			contentContainer.add(fp);
			fp.clear();
		}
		glassPane.repaint();
		choosePanels.clear();
	}

	public boolean isMaxChoosed()
	{
		return choosePanels.size() == maxChooseNum;
	}

	public void delete(FoodPanel fp)
	{
		ArrayList<FoodPanel> panels = getCurrentPanels();
		int index = panels.indexOf(fp);
		positionConfiger.removePositionSetter(index);
		panels.remove(index);
		contentContainer.remove(fp);
		scrollPane.revalidate();
		scrollPane.repaint();
		boolean isBreakfast = mainFrame.isSelectBreakfast();
		categoryData.delete(index, isBreakfast);
	}

	private FileDialog fileDialog;
	void addNew()
	{
		if (fileDialog == null)
		{
			fileDialog = NativeTools.createNativeFileDialog(this, "",
					FileDialog.LOAD, ImageTools.pictureExts);
			fileDialog.setMultipleMode(true);
		}
		fileDialog
				.setTitle("添加新菜单 — 选择" + categoryData.getCategoryName() + "图片");
		fileDialog.setVisible(true);
		File[] files = fileDialog.getFiles();
		if (files.length < 1)
			return;

		boolean isBreakfast = mainFrame.isSelectBreakfast();
		String fileName, foodName;
		for (File imgFile : files)
		{
			fileName = imgFile.getName();
			if (!ImageTools.isNormalImage(fileName))
			{
				JOptionPane.showMessageDialog(this,
						fileName + "文件出错！请选择jpg、png和bmp格式的图片。", "添加新菜单",
						JOptionPane.OK_OPTION);
				continue;
			}
			Image image = ResourceManager.getImage(imgFile);
			if (image == null)
				continue;
			ImageTools.loadImage(image);
			//image=new ImageIcon(image).getImage();

			if (image.getWidth(null) < 80
					|| image.getHeight(null) < 60)
			{
				JOptionPane.showMessageDialog(this,
						fileName + "图片尺寸太小！请选择大小合适的图片。", "添加新菜单",
						JOptionPane.OK_OPTION);
				continue;
			}
			foodName = TextTools.getFileNameNoExt(fileName);
			categoryData.addNew(imgFile, foodName, isBreakfast, this);
		}
	}

	void addNewFood(FoodData foodData, boolean isBreakfast)
	{
		ArrayList<FoodPanel> choosePanels, unchoosePanels;
		if (isBreakfast)
		{
			choosePanels = breakfastPanels;
			unchoosePanels = otherPanels;
		} else
		{
			choosePanels = otherPanels;
			unchoosePanels = breakfastPanels;
		}
		FoodPanel foodPanel;
		if (foodData.isInBoth())
			foodPanel = findFoodPanel(unchoosePanels, foodData);
		else
			foodPanel = new FoodPanel(foodData, this);
		foodPanel.setEditable(editable);
		choosePanels.add(foodPanel);

		if (isBreakfast == mainFrame.isSelectBreakfast())
		{
			positionConfiger.addPositionSetter(foodPanel);
			contentContainer.add(foodPanel);
			scrollPane.revalidate();
			scrollPane.repaint();
		}
	}

	private FoodPanel findFoodPanel(ArrayList<FoodPanel> foodPanels,
			FoodData foodData)
	{
		for (FoodPanel foodPanel : foodPanels)
			if (foodPanel.foodData == foodData)
				return foodPanel;
		return null;
	}

	public int getPreferredWidth()
	{
		Insets insets = getInsets();
		int width = insets.left + insets.right;
		if (positionConfiger != null)
			width += positionConfiger.getPreferredWidth();
		return width;
	}

	public static int getPreferredHeight(int h, int s, int upB)
	{
		return 26 + upB + (MainApp.maxRow) * (h + s) + h + 16 + 10;
	}

	@Override
	public void setBounds(int x, int y, int width, int height)
	{
		if ((getWidth() == width && getHeight() == height)
				|| positionConfiger == null)
		{
			super.setBounds(x, y, width, height);
			return;
		}

		Insets insets = getInsets();
		int ww = width - insets.left - insets.right;
		// int hh = height - insets.top - insets.bottom;
		if (MainApp.isExtendMode)
			positionConfiger.caculateMaxColumn(ww, MainFrame.minLeftB);

		titleComp.setBounds(3, 6, width - 6, 20);
		int h = positionConfiger.getH() + 16;
		int yy = height - h - 10;
		choosePane.setBounds(10, yy, width - 20, h);
		if (addButton != null)
			addButton.setBounds((width - 105) / 2, yy + h / 2 - 16, 105, 32);

		h = yy - 26;
		scrollPane.setBounds(insets.left, 26, ww, h);
		glassPane.setBounds(0, 0, width, height);

		yy += 8;
		int pS = positionConfiger.getS();
		int pWS = positionConfiger.getW() + pS;
		int xx = (width - breakfastChooseNum * pWS + pS) / 2;
		for (Position position : breakfastChoosePositions)
		{
			position.setY(yy);
			position.setX(xx);
			xx += pWS;
		}

		xx = (width - otherChooseNum * pWS + pS) / 2;
		for (Position position : otherChoosePositions)
		{
			position.setY(yy);
			position.setX(xx);
			xx += pWS;
		}
		int i = 0;
		for (FoodPanel fp : choosePanels)
		{
			fp.setBounds(choosePositions[i].getX(), choosePositions[i].getY(),
					choosePositions[i].getW(), choosePositions[i].getH());
			i++;
		}
		super.setBounds(x, y, width, height);
	}

	private final String[] options = {"确定", "取消",};
	private Object[] editDialogObjects;
	private JTextField nameField;
	private JCheckBox isMainFoodBox, isMainDishesBox;

	private void showEditDialog()
	{
		if (editDialogObjects == null)
		{
			editDialogObjects = new Object[3];
			JPanel panel1 = new JPanel();
			panel1.add(new JLabel("类别名称："));
			nameField = new JTextField(8);
			nameField.setText(categoryData.getCategoryName());
			panel1.add(nameField);
			editDialogObjects[0] = panel1;
			JPanel panel2 = new JPanel();
			editDialogObjects[1] = panel2;
			isMainFoodBox = new JCheckBox("是 否 为 主 食");
			panel2.add(isMainFoodBox);
			JPanel panel3 = new JPanel();
			editDialogObjects[2] = panel3;
			isMainDishesBox = new JCheckBox("是否为主菜(汤)");
			panel3.add(isMainDishesBox);
		}
		isMainFoodBox.setSelected(categoryData.isMainFood());
		isMainDishesBox.setSelected(categoryData.isMainDishes());
		int optionResult = ROptionPane.showOptionDialog(this, editDialogObjects,
				"编辑-" + categoryData.getCategoryName(), Color.yellow,
				JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE, null,
				options, null);
		if (optionResult == 0)
		{
			String name = nameField.getText();
			if (categoryData.getCategoryName() != name
					&& !TextTools.isBlank(name))
			{
				titleComp.setText(name);
				categoryData.setCategoryName(name);
				if (MainApp.isExtendMode)
				{
					JTabbedPane pane = mainFrame.getTabbedPane();
					pane.setTitleAt(pane.indexOfComponent(this),
							" " + name + " ");
				}
			}
			categoryData.setMainFood(isMainFoodBox.isSelected());
			categoryData.setMainDishes(isMainDishesBox.isSelected());
		}
	}

	class ContentContainer extends Container
	{
		private static final long serialVersionUID = 3680857505847408720L;
		private JScrollPane scrollPane;
		private final Dimension preferredSize = new Dimension();

		@Override
		public Dimension getPreferredSize()
		{
			if (positionConfiger != null)
			{
				preferredSize.width = positionConfiger.getPreferredWidth()
						- RScrollBarUI.barWidth;
				preferredSize.height = positionConfiger.getPreferredHeight();
				return preferredSize;
			}
			return super.getPreferredSize();
		}

		public JScrollPane getScrollPane()
		{
			if (scrollPane == null)
				scrollPane = new JScrollPane(this);
			return scrollPane;
		}
	}

	class GlassPanel extends JComponent
	{
		private static final long serialVersionUID = 388995919267499878L;

		@Override
		protected void paintComponent(Graphics g)
		{
			// super.paintComponent(g);
			if (choosePositions == null || editable)
				return;
			Graphics2D g2d = (Graphics2D) g;
			Stroke oldStroke = g2d.getStroke();
			g2d.setStroke(GraphicsTools.getDottedStroke());
			g2d.setColor(Color.gray);
			for (Position p : choosePositions)
			{
				if (!p.isUsed())
					g2d.drawRoundRect(p.getX() + 2, p.getY() + 2, p.getW() - 6,
							p.getH() - 6, 8, 8);
			}
			g2d.setStroke(oldStroke);
		}
	}
}
